package service.exportation;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import javax.annotation.Resource;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import org.codehaus.stax2.XMLStreamWriter2;
import org.springframework.stereotype.Service;
import service.configuration.IConfiguration;
import service.sheetmanager.SheetManager;
import service.treemanager.ITreeManager;
import web.form.Block;
import web.form.Item;
import web.form.SheetType;
import web.form.SheetView;


@Service
public class Exporter implements IExporter {
	
	@Resource
	private IConfiguration config;
	
	@Resource
	private SheetManager sheetManager;
	
	@Resource
	private ITreeManager treeManager;

	
	private void writeSheet(SheetView sheetView, XMLStreamWriter2 xtw) throws XMLStreamException {
		xtw.writeStartElement("SHEET_" + sheetView.getType());
		xtw.writeAttribute("id", sheetView.getCode().trim());
		
		xtw.writeStartElement("TITLE");
		xtw.writeCData(sheetView.getTitle());
		xtw.writeEndElement(); //title
		
		xtw.writeStartElement("STATUS");
		xtw.writeRaw(sheetView.getStatus().toString());
		xtw.writeEndElement(); //status
		
		for(Block block : sheetView.getBlocks()) {
			if(block.getItems() == null) {
				continue;
			}
			
			xtw.writeStartElement("BLOCK");
		
			xtw.writeStartElement("LABEL");
			xtw.writeRaw(block.getLabel());
			xtw.writeEndElement(); //label
			
			for(Item item : block.getItems()) {
				if(item != null) {
					xtw.writeStartElement("ITEM");
					
					xtw.writeStartElement("LABEL");
					xtw.writeRaw(item.getLabel());
					xtw.writeEndElement(); //label
					
					xtw.writeStartElement("VALUE");
					if(item.getValue() != null) {
						xtw.writeCData(item.getValue());
					}
					xtw.writeEndElement(); //value
					
					xtw.writeEndElement(); //item	
				}
			}
			
			xtw.writeEndElement(); //sheet type
		}

		for(SheetType type : treeManager.getChildrenTypes(sheetView.getCode())) {
			xtw.writeStartElement("CHILD_" + type.getName());

			for(String childCode : treeManager.getChildrenCodes(sheetView.getCode(), type.getName())) {
				xtw.writeStartElement("CHILD");
				xtw.writeAttribute("ref", childCode.trim());
				xtw.writeEndElement(); //child
			}
			
			xtw.writeEndElement(); //type
		}
		
		xtw.writeEndElement(); //sheet
	}
	
	/**
	 * Génére un fichier XML d'export et une DTD le validant dans le daossier précisé en paramètre.
	 * Le fichier XML est nommé AsofExport.xml.
	 * Le fichier DTD est nommé AsofExport.dtd.
	 * 
	 * @param folderPath dossier dans lequel sera créé les fichiers
	 */
	public void export(String folderPath) throws XMLStreamException, IOException {	
		String filePath = folderPath + "AsofExport.xml";
		XMLOutputFactory xof = XMLOutputFactory.newInstance();
		XMLStreamWriter2 xtw = (XMLStreamWriter2) xof.createXMLStreamWriter(new FileWriter(filePath));
		
		xtw.writeStartDocument();
		xtw.writeDTD("<!DOCTYPE ASOFEXPORT SYSTEM \"AsofExport.dtd\">");
		xtw.writeStartElement("ASOFEXPORT");
		
		for(String type : config.getSheetTypes()) {			
			for(SheetView sheetView : sheetManager.findAllSheets(type)) {
				writeSheet(sheetView, xtw);
			}
		}
		
		xtw.writeEndElement(); //asofexport
		xtw.writeEndDocument();
		
		xtw.flush();
		xtw.close();

		generateDTD(folderPath);
	}

	private void generateDTD(String folderPath) throws IOException {
		String filePath = folderPath + "AsofExport.dtd";
		FileWriter fw = new FileWriter(filePath);
		BufferedWriter bw = new BufferedWriter(fw);
		List<String> sheetTypes = config.getSheetTypes();

		bw.write("<!ELEMENT ASOFEXPORT (");
		for(int i = 0; i < sheetTypes.size() - 1; i++) {
			bw.write("SHEET_" + sheetTypes.get(i));
			bw.write("*, ");
		}
		bw.write("SHEET_" + sheetTypes.get(sheetTypes.size() - 1));
		bw.write("*)>\n");
		
		for(String type : sheetTypes) {
			bw.write("<!ELEMENT ");
			bw.write("SHEET_" + type);
			bw.write(" (TITLE, STATUS, BLOCK*");
			
			List<String> childrenTypes = config.getChildrenTypes(type);
			if(!childrenTypes.isEmpty()) {
				bw.write(", (");
				for(int i = 0; i < childrenTypes.size() - 1; i++) {
					bw.write("CHILD_" + childrenTypes.get(i));
					bw.write(" | ");
				}
				bw.write("CHILD_" + childrenTypes.get(childrenTypes.size() - 1));
				bw.write(")*");
			}
			bw.write(")>\n");
			
			bw.write("<!ELEMENT CHILD_" + type + " (CHILD*)>\n");
		}
		
		bw.write("<!ELEMENT TITLE (#PCDATA)>\n");
		bw.write("<!ELEMENT STATUS (#PCDATA)>\n");
		
		bw.write("<!ELEMENT BLOCK (LABEL, ITEM*)>\n");
		bw.write("<!ELEMENT LABEL (#PCDATA)>\n");
		bw.write("<!ELEMENT ITEM (LABEL, VALUE)>\n");
		bw.write("<!ELEMENT VALUE (#PCDATA)>\n");
		
		bw.write("<!ELEMENT CHILD EMPTY>\n");
		
		for(String type : sheetTypes) {
			bw.write("<!ATTLIST SHEET_" + type + " id ID #REQUIRED>\n");
		}
		
		bw.write("<!ATTLIST CHILD ref IDREF #REQUIRED>\n");
		
		bw.flush();
		bw.close();
	}
	
}
